/**
 * @file drv_ws2812.h
 * @author Blues Jiang
 * @brief Modified from what maplerian wrote.
 * @version 0.1
 * @date 2022-03-23
 *
 * @copyright Copyright (c) 2022
 *
 */

#ifndef __DRV_WS2812_H__
#define __DRV_WS2812_H__

#include <rtthread.h>
#include <rtdevice.h>

/**
 * @brief Information of WS2812B
 * Timing of 1 bit: 1250ns±600ns
 * High voltage time of 0 code(T0H): 400ns±150ns
 * Low voltage time of 0 code(T0L): 800ns±150ns
 * High voltage time of 1 code(T1H): 850ns±150ns
 * Low voltage time of 1 code(T1L): 450ns±150ns
 * Older WS2812s can handle a reset time (TRST) of 50us,
 * but recent component revisions require a minimum of 280us.
 * Low voltage time of reset(TRES): About 280000ns
 */

#ifdef RGBW
    #define LED_TYPE cRGBW
#else
    #define LED_TYPE RGB
#endif

#define WS2812_BYTE_ORDER_RGB 0
#define WS2812_BYTE_ORDER_GRB 1
#define WS2812_BYTE_ORDER_BGR 2

#ifndef WS2812_BYTE_ORDER
    #define WS2812_BYTE_ORDER WS2812_BYTE_ORDER_GRB
#endif

typedef struct PACKED
{
    #if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
    rt_uint8_t g;
    rt_uint8_t r;
    rt_uint8_t b;
    #elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
    rt_uint8_t r;
    rt_uint8_t g;
    rt_uint8_t b;
    #elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
    rt_uint8_t b;
    rt_uint8_t g;
    rt_uint8_t r;
    #endif
} cRGB;

typedef cRGB RGB;

// WS2812 specific layout
typedef struct
{
    #if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
    rt_uint8_t g;
    rt_uint8_t r;
    rt_uint8_t b;
    #elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB)
    rt_uint8_t r;
    rt_uint8_t g;
    rt_uint8_t b;
    #elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR)
    rt_uint8_t b;
    rt_uint8_t g;
    rt_uint8_t r;
    #endif
    rt_uint8_t w;
} cRGBW_t;

typedef struct
{
    rt_uint8_t h;
    rt_uint8_t s;
    rt_uint8_t v;
} HSV_t;


#define WS2812_MAX_FREQ 10000000 //5MHz,4.5MHz is fine

//  一位占用多少个字节
// 首先,确定WS2812的一位需要SPI的多少位表示
// 表示可能存在非整8位的情况,如现在使用用6位SPI表示1位颜色
// 显示出对应1位颜色值位0/1时SPI需要发送的值
// 然后取6与8的最小公倍数
// 需要处理完几个byte后发送
#define OneBitOccupySPIBit  6
#define BitsNumWhenSPIBitIsDivisible 4
#define OneNodeBuffLength (8 * 3 * OneBitOccupySPIBit / 8)

#define SPIBitValid     ((1<<(OneBitOccupySPIBit))-1)
#define SPIBit_value1   0x3C
#define SPIBit_value0   0x30

struct ws2812_dev
{
    struct rt_spi_device *spi;
    rt_uint8_t *buff;
    uint16_t node_len;
};
typedef struct ws2812_dev *ws2812_dev_t;

ws2812_dev_t ws2812_create(char *spi_name, uint16_t led_node_length);
void ws2812_clear_buff(ws2812_dev_t ws2812);
void ws2812_write_rgb_to_node(ws2812_dev_t ws2812, uint16_t index, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b);
void ws2812_write_rgb_to_all(ws2812_dev_t ws2812, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b);
void ws2812_write_rgb_to_all_24bit(ws2812_dev_t ws2812, uint32_t rgb);
void ws2812_send(ws2812_dev_t ws2812);

#endif  /* __DRV_WS2812_H__ */
